package auctionhaus
//Authors: Paul Kleczka, Adam Backstrom

import grails.test.mixin.*
import org.junit.*

/**
 * See the API for {@link grails.test.mixin.domain.DomainClassUnitTestMixin} for usage instructions
 */
@TestFor(Listing)
class ListingTests {

    //L-1,L-2,L-3
    void testValidListing() {
        
        String name = "listing"
        Date endDateTime = new Date() + 2
        Float startingBidPrice = 32.50

        Listing listing = new Listing(name: name,
                                      endDateTime: endDateTime,
                                      startingBidPrice: startingBidPrice,
                                      seller: new Customer())
        listing.save(flush: true)

        assert listing.validate()

        Listing foundListing = Listing.findByName(name)

        assert foundListing
        assert foundListing.name
        assert foundListing.endDateTime
        assert foundListing.startingBidPrice
        assert foundListing.seller
        
    }

    //L-1, L-2, L-3
    void TestValidListingWithDescription() {

        String name = "listingWithDescription"
        Date endDateTime = new Date() + 2
        Float startingBidPrice = 32.50

        String description = "Listing description."

        Listing listing = new Listing(name: name,
                endDateTime: endDateTime,
                startingBidPrice: startingBidPrice,
                seller: new Customer(),
                description: description)
        listing.save(flush: true)

        assert listing.validate()

        Listing foundListing = Listing.findByName(name)

        assert foundListing
        assert foundListing.name
        assert foundListing.endDateTime
        assert foundListing.startingBidPrice
        assert foundListing.seller

        assert foundListing.description
    }

    //L-1, L-3
    void testNullables(){
        
        Listing l = new Listing()
        l.save(flush: true)

        assert !l.validate()

        assertEquals 'nullable',l.errors['name'].code
        assertEquals 'nullable',l.errors['endDateTime'].code
        assertEquals 'nullable',l.errors['seller'].code
    }

    //L-1
    void testBlankName(){
        Listing l = new Listing(name: "")
        l.save(flush:  true)

        assert !l.validate()

        assertEquals  'blank',l.errors['name'].code

    }


    //L-6
    void testInvalidName(){
        
        //create a string with 64 chars
        String s = ""
        (1..64).toArray().each {
           s+="a"
        }
        assertEquals 64,s.size()
        
        Listing l = new Listing(name: s)
        l.save(flush: true)
        assert !l.validate()

        assertEquals 'maxSize.exceeded',l.errors['name'].code

    }

    //L-6
    void testValidName(){

        //test a string with one character
        String s1 = "a"

        //test string with 63 characters
        String s2 = ""
        (1..63).toArray().each{
            s2+="b"
        }
        assertEquals 63,s2.size()

        //test string with 32 characters
        String s3 = ""
        (1..32).toArray().each{
            s3+="c"
        }
        assertEquals 32,s3.size()

        def validNames = [s1,s2,s3]

        validNames.each {

            Listing l = new Listing(name: it)
            l.save(flush: true)

            assertNull l.errors['name']
        }
    }

    //L-5
    void testInvalidEndDateTime(){

        def listings = [
            new Listing(endDateTime: new Date()),
            new Listing(endDateTime: new Date()-1)
        ]

        listings.each{
                it.save(flush: true)
                assert !it.validate()
                assertEquals 'validator.invalid',it.errors['endDateTime'].code
        }
    }

    //L-5
    void testValidEndDateTime(){

        def millis = Calendar.instance.time.time
        millis += 60*1000

        //don't have to to .longValue() but get warning if you don't
        Date oneMinuteFromNow = new Date(millis.longValue())
  
        def listings = [
                new Listing(endDateTime:  new Date() + 1),
                new Listing(endDateTime:  new Date() + 50000),
                new Listing(endDateTime:  oneMinuteFromNow)
        ]
        
        listings.each{
            it.save(flush: true)
            assertNull it.errors['endDateTime']
        }
    }

    //no specific requirement, but price must be greater than one cent
    void testInvalidStartingBidPrice(){

        def listings = [
                new Listing(startingBidPrice: -1),
                new Listing(startingBidPrice: -0.01),
                new Listing(startingBidPrice: -10000.00001),
                new Listing(startingBidPrice: 0),
                new Listing(startingBidPrice:  0.009)
        ]
        
        listings.each{
            it.save(flush: true)
            assert !it.validate()
            assertEquals 'min.notmet',it.errors['startingBidPrice'].code
        }
    }

    //L-1
    void testValidStartingBidPrice(){

        def listings = [
                new Listing(startingBidPrice: 0.01),
                new Listing(startingBidPrice: 1.01),
                new Listing(startingBidPrice: 10000.01),
                new Listing(startingBidPrice: 1000000)
        ]

        listings.each{
            it.save(flush: true)
            assertNull it.errors['startingBidPrice']
        }

    }

    //L-2, L-4
    void testValidDescription(){

        //test string with 255 characters
        String maxCharsMinusOne = ""
        (1..254).toArray().each{
            maxCharsMinusOne+="c"
        }
        assertEquals 254,maxCharsMinusOne.size()

        //test string with 256 characters
        String maxChars = maxCharsMinusOne + "a"
        assertEquals 255,maxChars.size()
        
        //ok to be null
        def listings = [
                new Listing(description: null),
                new Listing(),
                new Listing(description: ""),
                new Listing(description: "        "),
                new Listing(description: "this is a valid description."),
                new Listing(description: maxCharsMinusOne),
                new Listing(description: maxChars)
        ]
        
        listings.each{
            it.save(flush: true)
            assertNull it.errors['description']
        }
    }           

    //L-4
    void testInvalidDescription(){
        
        //test string with 257 characters
        String maxCharsPlusOne = ""
        (1..256).toArray().each{
            maxCharsPlusOne+="c"
        }
        assertEquals 256,maxCharsPlusOne.size()
        
        def listings = [
                new Listing(description: maxCharsPlusOne),
                new Listing(description: maxCharsPlusOne + maxCharsPlusOne)
        ]
        
        listings.each{
            it.save(flush: true)
            assert !it.validate()
            assertEquals 'maxSize.exceeded',it.errors['description'].code
        }
    }

    //L-7
    void testValidWinner(){

        def listings = [
                new Listing(),
                new Listing(winner: null),
                new Listing(winner:  new Customer()),
                new Listing(winner:  new Customer(email: "kleczka@gmail.com",password: "1234567"))
        ]
        
        listings.each{
            it.save(flush: true)
            assertNull it.errors['winner']
        }
    }

    //L-7
    void testInvalidSeller(){

        def listings = [
                new Listing(),
                new Listing(seller: null)
        ]
        
        listings.each{
            it.save(flush: true)
            assert !it.validate()
            assertEquals 'nullable',it.errors['seller'].code
        }
    }

    //L-7
    void testValidSeller(){

        Listing l = new Listing(seller: new Customer(email: "kleczka@gmail.com",password: "1234567"))
        l.save(flush: true)
        assertNull l.errors['seller']
    }


    //B-4: A Listing has a list of Bids for that Listing
    void testListingHasListOfBids()
    {
        Listing listing = new Listing(seller: new Customer(email: "adambackstrom@gmail.com",password: "1234567"))
        listing.bids = new ArrayList()

        Bid bid = new Bid(amount: 10f,
                bidDateTime: new Date(),
                listing:  listing,
                bidder:  new Customer() )
        listing.bids.add(bid)

        Bid secondBid = new Bid(amount: 10.5f,
                bidDateTime: new Date(),
                listing:  listing,
                bidder:  new Customer() )

        listing.bids.add(secondBid)
        listing.save(flush: true)

        //confirm that the listing has a list of 2 bids
        assert 2 == listing.bids.size()

        //confirm that the bids have the correct listing
        Bid listingBid = (Bid)listing.bids.get(0)
        assert listing == listingBid.getListing()
        listingBid = (Bid)listing.bids.get(1)
        assert listing == listingBid.getListing()
    }
}
